package com.zimin.common.utils;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.afterturn.easypoi.excel.export.ExcelBatchExportService;
import cn.afterturn.easypoi.handler.inter.IWriter;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.zimin.common.exception.GraceException;
import com.zimin.shared.enums.ResponseStatusEnum;
import org.apache.poi.openxml4j.util.ZipSecureFile;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbookType;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.List;

/**
 * @Author: 嘉阳
 * @Date: 2020/12/29
 * @Describe: Excel 工具类
 */
public class ExcelUtil {


    /**
     * 大数据导出 <p>直接下载</p>
     *
     * @param clz   class
     * @param title 文件标题
     * @return
     */
    public static ExcelBatchExportService getBigExcel(Class clz, String title) {
        ExcelBatchExportService batchServer = new ExcelBatchExportService();
        batchServer.init(new ExportParams(title, title), clz);
        return batchServer;
    }

    public static void writeBigExcel(ExcelBatchExportService excelBatchExportService, List<?> list) {
        excelBatchExportService.write(list);
        list.clear();
    }

    public static void exportBigExcel(ExcelBatchExportService excelBatchExportService, String fileName) {
        IWriter<Workbook> workbook = excelBatchExportService.write(Arrays.asList());
        excelBatchExportService.close();
        exportDownload(workbook.get(), fileName);
    }

    public static <T> void exportsDynamic(String fileName, List<ExcelExportEntity> entity, List<T> dtoLst, HttpServletResponse response) {
        try {
            // easyPoi操作excel
            Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), entity, dtoLst);
            // 设置响应头
            response.setHeader("content-Type", "application/vnd.ms-excel;charset=UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));
            // 写入到流中
            ServletOutputStream outputStream = response.getOutputStream();
            workbook.write(outputStream);
            workbook.close();
            outputStream.close();
        } catch (Exception e) {
            try {
                response.setHeader("Content-type", "text/html;charset=UTF-8");
                response.setCharacterEncoding("UTF-8");
                PrintWriter pw = response.getWriter();
                pw.write("导出文件异常！");
            } catch (Exception e1) {
//                log.error(e1.getMessage());
            }
        }
    }
    /**
     * 普通导出 <p>直接下载</p>
     *
     * @param clz       class
     * @param list      数据列表
     * @param fileName  文件名称
     * @param title     文件标题
     * @param sheetName sheet名称
     */
    public static void exports(Class clz, List<?> list, String fileName, String title, String sheetName) {
        exportDownload(ExcelExportUtil.exportExcel(new ExportParams(title, sheetName, ExcelType.XSSF), clz, list), fileName);
    }

    /**
     * 普通导出 <p>直接下载 适用于自定义导出信息</p>
     *
     * @param workbook workbook
     * @param fileName 文件名称
     */
    public static void exports(Workbook workbook, String fileName) {
        exportDownload(workbook, fileName);
    }

    /**
     * 普通导出 <p>返回文件路径</p>
     *
     * @param clz       class
     * @param list      数据列表
     * @param fileName  文件名称
     * @param title     文件标题
     * @param sheetName sheet名称
     * @return 文件名称
     */
    public static String export(Class clz, List<?> list, String fileName, String title, String sheetName) {
        return exportFilePath(ExcelExportUtil.exportExcel(new ExportParams(title, sheetName, ExcelType.XSSF), clz, list), fileName);
    }

    /**
     * 导入
     *
     * @param clz         class
     * @param inputStream 文件流
     * @return
     */
    public static <T> ExcelImportResult<T> imports(Class<T> clz, InputStream inputStream) {
        return imports(clz, inputStream, 0, 1);
    }

    /**
     * 导入
     *
     * @param clz         class
     * @param inputStream 文件流
     * @param titleRows   文件标题行
     * @param headerRows  文件表头行
     * @return 数据列表
     */
    public static <T> ExcelImportResult<T> imports(Class<T> clz, InputStream inputStream, Integer titleRows, Integer headerRows) {
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        // 2021年05月09日 支持并行计算 嘉阳
        params.setConcurrentTask(Boolean.TRUE);
        // 2021年05月09日 支持字段验证 嘉阳
        params.setNeedVerify(Boolean.TRUE);
        ZipSecureFile.setMinInflateRatio(-1.0d);
        try {
            return ExcelImportUtil.importExcelMore(inputStream, clz, params);
        } catch (Exception e) {
            GraceException.display(ResponseStatusEnum.IDEMPOTENCE_ERROR);
            return null;
        }
    }

    /**
     * 下载
     *
     * @param fileName 文件名称
     */
    public static void downLoads(String fileName) {
        downLoads(null, fileName);
    }

    /**
     * 下载
     *
     * @param path     文件路径
     * @param fileName 文件名称
     */
    public static void downLoads(String path, String fileName) {
        InputStream inputStream = null;
        ByteArrayOutputStream outStream = null;
        try {
            if (StrUtil.isBlank(path)) {
                // 读取缺省目录文件
                File file = new File(fileName);
                inputStream = new FileInputStream(file);
            } else {
                // 读取指定目录文件
                inputStream = ExcelUtil.class.getResourceAsStream(path + fileName);
            }
            outStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) != -1) {
                outStream.write(buffer, 0, length);
            }
            inputStream.close();
            download(outStream.toByteArray(), fileName);
        } catch (Exception e) {
            GraceException.display(ResponseStatusEnum.FILE_DOWNLOAD_FAIL);
        } finally {
            IoUtil.close(inputStream);
            IoUtil.close(outStream);
        }
    }

    /*********************************************************************************************************/

    /**
     * 导出 <p>直接下载</p>
     *
     * @param workbook workbook
     * @param fileName 文件名称
     */
    private static void exportDownload(Workbook workbook, String fileName) {
        ByteArrayOutputStream outputStream = null;
        try {
            outputStream = new ByteArrayOutputStream();
            workbook.write(outputStream);
            download(outputStream.toByteArray(), getFileName(fileName));
        } catch (Exception e) {
            GraceException.display(ResponseStatusEnum.FILE_DOWNLOAD_FAIL);
        } finally {
            IoUtil.close(workbook);
            IoUtil.close(outputStream);
        }
    }

    /**
     * 导出 <p>返回文件路径</p>
     *
     * @param workbook workbook
     * @param fileName 文件名称
     * @return
     */
    private static String exportFilePath(Workbook workbook, String fileName) {
        OutputStream outputStream = null;
        try {
            File file = FileUtil.touch(getFileName(fileName));
            outputStream = new FileOutputStream(file.getCanonicalPath());
            workbook.write(outputStream);
            return fileName;
        } catch (Exception e) {
            GraceException.display(ResponseStatusEnum.FILE_EXPORT_FAIL);
            return "";
        } finally {
            IoUtil.close(workbook);
            IoUtil.close(outputStream);
        }
    }

    /**
     * 文件名.xls
     *
     * @param fileName 文件名
     */
    private static String getFileName(String fileName) {
        return fileName + System.currentTimeMillis() + "." + XSSFWorkbookType.XLSX.getExtension();
    }

    /**
     * 流下载
     *
     * @param bytes    字节数组
     * @param fileName 文件名称
     */
    private static void download(byte[] bytes, String fileName) throws IOException {
        HttpServletResponse response = null;
        try {
            response = ServletUtil.getResponse();
        } catch (Exception e) {
            e.printStackTrace();
        }
        OutputStream outputStream;
        response.reset();
        // https://www.cnblogs.com/codesyofo/p/14142197.html 解决VUE无法读取文件名称的问题。
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition,fileName");
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fileName, "utf-8"));
        outputStream = response.getOutputStream();
        outputStream.write(bytes);
        outputStream.flush();
        outputStream.close();
    }


}
